from typing import Any, Optional, Iterator

from chernc.treediff.gumtree.tree.abstract_tree import AbstractTree
from chernc.treediff.gumtree.tree.tree import TreeLike


class DefaultTree(AbstractTree):
    """
    DefaultTree class representing a tree node with a specific type, label, and metadata.
    """

    def __init__(self, type_: str, label: Optional[str] = None):
        """
        Constructs a new node with the given type and label.
        If the label is None, it will be replaced by an empty string.
        """
        self.type = type_
        self.label = label if label is not None else 'NO_LABEL'
        self.children = []  # Empty list to hold child nodes
        self.pos = 0
        self.length = 0
        self.metadata = None

    def deep_copy(self) -> TreeLike:
        """
        Create a deep copy of this tree node, including its children.
        """
        copy = DefaultTree(self.type, self.label)
        copy.pos = self.pos
        copy.length = self.length
        for child in self.get_children():
            copy.add_child(child.deep_copy())
        return copy

    def get_label(self) -> str:
        """
        Get the label of the tree node.
        """
        return self.label

    def get_length(self) -> int:
        """
        Get the length of the tree node.
        """
        return self.length

    def get_pos(self) -> int:
        """
        Get the position of the tree node.
        """
        return self.pos

    def get_type(self) -> str:
        """
        Get the type of the tree node.
        """
        return self.type

    def set_label(self, label: str) -> None:
        """
        Set the label of the tree node.
        """
        self.label = label if label is not None else 'NO_LABEL'

    def set_length(self, length: int) -> None:
        """
        Set the length of the tree node.
        """
        self.length = length

    def set_pos(self, pos: int) -> None:
        """
        Set the position of the tree node.
        """
        self.pos = pos

    def set_type(self, t: str) -> None:
        """
        Set the type of the tree node.
        """
        self.type = t

    def get_metadata(self, key: str) -> Any:
        """
        Get the metadata associated with a key.
        """
        if self.metadata is None:
            return None
        return self.metadata.get(key)

    def set_metadata(self, key: str, value: Any) -> Any:
        """
        Set metadata for the tree node.
        If the value is None, it removes the metadata.
        """
        if value is None:
            if self.metadata is None:
                return None
            else:
                return self.metadata.pop(key, None)
        if self.metadata is None:
            self.metadata = {}
        previous_value = self.metadata.get(key)
        self.metadata[key] = value
        return previous_value

    def get_metadata_iterator(self) -> Iterator:
        """
        Get an iterator for the metadata.
        """
        if self.metadata is None:
            return iter([])
        return iter(self.metadata.items())

    def get_children(self):
        """
        Get the children of the tree node.
        """
        return self.children

    def add_child(self, child: TreeLike) -> None:
        """
        Add a child to the tree node.
        """
        self.children.append(child)
